/* engcur.c -- Holds the functions relatives to engcur operations
 *
 * Time-stamp: <2007-06-27 10:15:43 BRT Diogo F. S. Ramos>
 *
 *
 */
#include <stdlib.h>
#include <string.h>

#include "../includes/engcur.h"
#include "../includes/support.h"

#define MAX_SEEDS 10

/* Discipline ********************************************************/
/* Creating the new discipline */
discipline*
discipline_new( char *new_cod, char *new_name, int new_cred, int new_class )
{
    discipline *disc = NULL;
    disc = (discipline*) malloc( sizeof( discipline ) );

    str_create_copy_string( &(disc->cod), new_cod );
    str_create_copy_string( &(disc->name), new_name );
    disc->credits = new_cred;
    disc->class = new_class;
    disc->scheded = 0;
    disc->number_of_seeds = 0;
    disc->root_seed = NULL;
    disc->next = NULL;
        
    return disc;    
}
    
void
discipline_destroy( discipline *disc )
{
    seed *aux = disc->root_seed;
    seed *prev = aux;

    while( aux != NULL )
    {
	aux = aux->next;
	free( prev );
	prev = aux;
    }
    free(disc->name);
    free(disc->cod);
    free(disc);    
}

int
discipline_add_seed( discipline *disc, seed *see )
{
    seed* ret = discipline_get_seed( disc, see->day, see->begin, see->end );
    if( !(ret) &&
	(discipline_race_seed( disc, see ) ) )
    {
	disc->number_of_seeds++;
	see->next = disc->root_seed;
	disc->root_seed = see;
	return 1;
    }
    
    return 0;
}

int
discipline_race_seed( discipline *disc, seed *see )
{
    seed *seed_aux = NULL;

    seed_aux = disc->root_seed;
    while( seed_aux )
    {
	if( (see->day == seed_aux->day) &&
	    (see->begin < seed_aux->end ) )
	    return 0;
	seed_aux = seed_aux->next;
    }

    return 1;
}


int
discipline_remove_seed( discipline *disc, int day, int begin, int end )
{
    seed *aux = disc->root_seed;
    seed *prev = aux;

    if( aux != NULL )
    {
	if( (aux->day == day) &&
	    (aux->begin == begin) &&
	    (aux->end == end) )
	{
	    disc->root_seed = aux->next;
	    seed_destroy( aux );
	    disc->number_of_seeds--;
	    return 1;
	} else {
	    prev = aux;
	    aux = aux->next;
	    while( aux != NULL )
	    {
		if( (aux->day == day) &&
		    (aux->begin == begin) &&
		    (aux->end == end) )
		{
		    prev->next = aux->next;
		    seed_destroy( aux );
		    disc->number_of_seeds--;
		    return 1;
		}
		prev = aux;
		aux = aux->next;
	    }
	}    
    }
    return 0;
}

seed*
discipline_get_seed( discipline *disc, int day, int begin, int end )
{
    seed *aux = disc->root_seed;

    while( aux != NULL )
    {
	if( (aux->day == day) &&
	    (aux->begin == begin) &&
	    (aux->end == end) )
	{
	    return aux;
	}
	aux = aux->next;
    }
    
    return NULL;
}

void
discipline_print( discipline *disc )
{
    seed *aux = disc->root_seed;

    if( disc->scheded )
	printf("*** %s %d %s %d %d\n", disc->cod, disc->class, disc->name, disc->credits,
	       disc->number_of_seeds );
    else
	printf("%s %d %s %d %d\n", disc->cod, disc->class, disc->name, disc->credits,
	       disc->number_of_seeds );
    while( aux != NULL )
    {
	printf("  %d %d %d\n", aux->day, aux->begin, aux->end );
	aux = aux->next;
    }
}

seed*
discipline_get_next_seed( discipline *disc, seed *see )
{
    if( !see )
    {
	return disc->root_seed;
    } else {
	return see->next;
    }
    
}


/*********************************************************************/

/* Seeds *************************************************************/
seed*
seed_new( int new_day, int new_begin, int new_end )
{
    seed *see;
    see = (seed*) malloc( sizeof( seed ) );

    see->day = new_day;
    see->begin = new_begin;
    see->end = new_end;
    see->next = NULL;
  
    return see;
}

void
seed_destroy( seed *see )
{
    free( see );
    
    return;
}


/*********************************************************************/

/* Semester **********************************************************/
/* The concep of semester is to have a struct to hold
 * "disciplines". Although the GtkTreeStore already stores it, I thing
 * it is more "right" to have an actual struct doing it. So, here we
 * are. */

semester*
semester_new()
{
    semester *sem = NULL;
    sem = (semester*) malloc( sizeof( semester ) );

    sem->number_of_disciplines = 0;
    sem->number_of_scheduled = 0;
    sem->root_discipline = NULL;
    return sem;
}

int
semester_add_discipline( semester *sem, discipline *disc )
{
    discipline *ret = semester_get_discipline( sem, disc->cod, disc->class );
    if( !ret )
    {
	sem->number_of_disciplines++;
	disc->next = sem->root_discipline;
	sem->root_discipline = disc;
	return 1;
    }
    
    return 0;
}

int
semester_remove_discipline( semester *sem, char *cod, int class )
{
    discipline *aux = sem->root_discipline;
    discipline *prev = aux;

    if( aux != NULL )
    {
	if( !strcmp(aux->cod, cod) &&
	    (aux->class == class) )
	{
	    sem->root_discipline = aux->next;
	    discipline_destroy( aux );
	    sem->number_of_disciplines--;
	    return 1;
	} else {
	    prev = aux;
	    aux = aux->next;
	    while( aux != NULL )
	    {
		if( !strcmp(aux->cod, cod) &&
		    (aux->class == class) )
		{
		    prev->next = aux->next;
		    discipline_destroy( aux );
		    sem->number_of_disciplines--;
		    return 1;
		}
		prev = aux;
		aux = aux->next;
	    }
	}    
    }
    return 0;
}

discipline*
semester_get_discipline( semester *sem, char *cod, int class )
{    
    discipline *aux = sem->root_discipline;

    while( aux != NULL )
    {
	if( !strcmp(aux->cod, cod) &&
	    (aux->class == class) )
	{
	    return aux;
	}
	aux = aux->next;
    }
    
    return NULL;
}

discipline*
semester_get_next_discipline( semester *sem, discipline *disc )
{
    if( !disc )
	return sem->root_discipline;
    else
	return disc->next;
}


void
semester_print( semester *sem )
{
    discipline *aux = sem->root_discipline;

    printf("/******************/\n");

    while( aux )
    {
	discipline_print( aux );
	aux = aux->next;
    }        
    printf("/******************/\n");

    return;
}

int
semester_schedule_add_discipline( semester *sem, discipline *disc )
{
    discipline *ret = semester_get_discipline( sem, disc->cod, disc->class );
    
    if( (ret) &&
	(ret->scheded == 0) &&
	semester_schedule_race_discipline( sem, ret ))
    {
	ret->scheded = 1;
	sem->number_of_scheduled++;
	return 1;
    }
    
    return 0;
}

int
semester_schedule_race_discipline( semester *sem, discipline *disc )
{
    discipline *disc_aux = NULL;
    seed *seed_aux = NULL;
    seed *seed_disc = NULL;

    seed_disc = disc->root_seed;
    if( !seed_disc )
	return 0;
    
    disc_aux = sem->root_discipline;

    while( disc_aux )
    {
	if( strcmp( disc_aux->cod, disc->cod ) &&
	    ( disc_aux->class != disc->class ) )
	{
	    seed_aux = disc_aux->root_seed;
	
	    while( seed_aux )
	    {
		while( seed_disc )
		{
		    if( (seed_disc->day == seed_aux->day) &&
			(seed_disc->begin < seed_aux->end ) )
			return 0;
		    seed_disc = seed_disc->next;
		}
		seed_disc = disc->root_seed;
		seed_aux = seed_aux->next;
	    }
	}
	
	disc_aux = disc_aux->next;
    }
    
    return 1;
}


int
semester_schedule_remove_discipline( semester *sem, discipline *disc )
{
    discipline *ret = semester_get_discipline( sem, disc->cod, disc->class );
    if( (ret) &&
	(ret->scheded) )
    {
	ret->scheded = 0;
	sem->number_of_scheduled--;
	return 1;
    }
    return 0;
}

void
semester_destroy( semester *sem )
{
    discipline *aux = sem->root_discipline;
    discipline *prev = aux;

    while( aux )
    {
	aux = aux->next;
	discipline_destroy( prev );
	prev = aux;
    }
    free( sem );
    
    return;
}


/*********************************************************************/
